﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using Web7.Core.InversionOfControl;
using Web7.Core.Configuration;
using Web7.Extensions;
using Web7.Ioc;

namespace Web7.Core.Apps
{
    public class AppRegistry : IAppRegistry, IDependencyDemandBuilder
    {
        private readonly IDependencyInjector _dependencyInjector;
        private readonly List<IApp> _apps;


        public AppRegistry()
        {
            this._apps = new List<IApp>();
        }

        public AppRegistry(IDependencyInjector dependencyInjector)
        {
            this._dependencyInjector = dependencyInjector;
            this._apps = new List<IApp>();
        }

        #region IModulesLoaded Members

        public IApp Load(Web7ConfigurationSection config, Web7AppConfigurationElement app)
        {
            // 如果module为null或module未启用
            if (app == null || !app.Enabled) return null;

            #region 遍历配置文件中的dataProviders节点下的元素
            foreach (Web7DataProviderConfigurationElement dataProvider in config.Providers)
            {
                // 如果dataProviders节点下的元素的name属性的值，和module的dataProvider属性值相等
                // 创建相关IWeb7DataProvider实例并执行ConfigureProvider方法以配置数据代理相关的信息
                if (dataProvider.Name == app.DataProvider)
                {
                    Type dataProviderType = Type.GetType(dataProvider.Type);

                    if (dataProviderType == null)
                        throw new TypeLoadException("Could not load type '{0}'.".FormatWith(dataProvider.Type));

                    //IDataProvider dataProviderInstance = _dependencyInjector.GetService(dataProviderType) as IDataProvider;

                    var dataProviderInstance = Activator.CreateInstance(dataProviderType) as IDataProvider;  //改为反射，不用DI


                    if (dataProviderInstance != null)
                    {
                        //dataProviderInstance.ConfigureProvider(config, dataProvider, _dependencyInjector); //todo:暂时注释
                    }

                    break;
                }
            }
            #endregion

            Type type = GetAppType(app.Type);

            // 根据类型获取IApp实例
            //IApp appInstance = _dependencyInjector.GetService(type) as IApp;
            var appInstance = Activator.CreateInstance(type) as IApp; //暂时用反射

            // 获取模块设置
            appInstance.Settings = app.Settings.ToNameValueCollection();

            // 将IApp实例放入容器中
            _apps.Add(appInstance);

            //注册当前容器的依赖关系
            //_dependencyInjector.RegisterAssembly(appInstance.GetType().Assembly); //todo:注册当前容器依赖关系

            // 返回IApp实例
            return appInstance;
        }


        public IEnumerable<IApp> GetApps()
        {
            return GetApps<IApp>();
        }

        public IEnumerable<T> GetApps<T>() ///where T : IApp
        {
            return _apps.OfType<T>();
        }

        public void UnloadApps()
        {
            foreach (IApp app in _apps)
                app.Unload();

            _apps.Clear();
        }

        #endregion


        private Type GetAppType(string typeStr)
        {
            // 根据module的type属性在引用程序集中获取类型
            Type type = Type.GetType(typeStr);

            // 如果在引用程序集中无法获取类型，则尝试从App_Code目录生成的程序集中获取
            if (type == null && BuildManager.CodeAssemblies != null)
                foreach (var assembly in BuildManager.CodeAssemblies)
                {
                    type = ((Assembly)assembly).GetExportedTypes().FirstOrDefault(t => t.FullName == typeStr);

                    if (type != null) break;
                }
            // 如果从以上两种途径都无法获取类型，抛出异常
            if (type == null)
            {
                throw new TypeLoadException("Could not load type '{0}'.".FormatWith(typeStr));
            }
            return type;

        }

        public void Build(IWeb7ContainerBuilder containerBuilder, IBuilderContext context)
        {
            //todo:注册该APP所处程序集的继承了IDependency接口类型

            //containerBuilder.ForFactory(
            //    x =>
            //    {
            //        var apps = x.Resolve<Web7ConfigurationSection>().Apps;
            //        foreach (Web7AppConfigurationElement app in apps)
            //        {
            //           GetAppType(app.Type);
            //        }
            //        return x;
            //    });
        }
    }
}
